package elephant.servers.webserver.core;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 
 * @author icecooly
 *
 */
public class Controller implements Comparable<Controller>{
	public Map<String,WebService>methodStubs;
	public WebService indexMethod;
	public Object instance;
	public String id;
	public Method beforeInvokeMethod;
	public Method afterInvokeMethod;
	//
	public Controller(String id) {
		this.id=id;
		methodStubs=new ConcurrentHashMap<String, WebService>();
	}
	//
	public WebService getMethod(String id){
		return methodStubs.get(id);
	}
	//
	public void setInstance(Object instance){
		this.instance=instance;
		//
		for(Method m:instance.getClass().getMethods()){
			RequestMapping anno=m.getDeclaredAnnotation(RequestMapping.class);
			if(anno!=null){
				addWebService(m,anno);
			}
			BeforeWebServiceAnno beforeAnno=m.getDeclaredAnnotation(BeforeWebServiceAnno.class);
			if(beforeAnno!=null){
				setBeforeWebService(m,beforeAnno);
			}
			AfterWebServiceAnno afterAnno=m.getDeclaredAnnotation(AfterWebServiceAnno.class);
			if(afterAnno!=null){
				setAfterWebService(m,afterAnno);
			}
		}
	}
	//
	private void addWebService(Method m,RequestMapping srv){
		if(!m.getReturnType().equals(void.class)){
			throw new IllegalArgumentException("ret must be void.method:"+
					instance.getClass().getSimpleName()+"."+m.getName()+"/"+m.getReturnType());
		}
		//
		if(m.getParameterTypes().length<1||
				!m.getParameterTypes()[0].equals(Context.class)){
			throw new IllegalArgumentException("parameter must be Context.method:"+m.getName());		
		}
		if(srv.id()==null){
			throw new IllegalArgumentException("service id can not be null.");	
		}
		WebService ms=new WebService();
		ms.controllerId=id;
		ms.id=srv.id();
		ms.index=srv.index();
		ms.methodName=srv.method().toString();
		ms.invokeMethod=m;
		methodStubs.put(srv.id(),ms);
		//
		if(srv.index()){
			indexMethod=ms;
		}
	}
	//
	private void setBeforeWebService(Method m,BeforeWebServiceAnno srv){
		this.beforeInvokeMethod=m;
	}
	//
	private void setAfterWebService(Method m,AfterWebServiceAnno srv){
		if(m.getParameterTypes().length!=2||
				!(m.getParameterTypes()[0].equals(Context.class)&&
						m.getParameterTypes()[1].equals(Throwable.class))){
			throw new IllegalArgumentException("afterInvokeMethod parameter must be (Context,Throwable)");		
		}
		this.afterInvokeMethod=m;
	}
	//
	public List<WebService>methodStubs(){
		return new ArrayList<WebService>(methodStubs.values());
	}
	//
	public int compareTo(Controller o) {
		return id.compareTo(o.id);
	};
	//
	@Override
	public String toString() {
		return id;
	}
}